package com.lframework.xingyun.basedata.impl.member;

import com.lframework.starter.common.utils.Assert;
import com.lframework.starter.web.core.annotations.oplog.OpLog;
import com.lframework.starter.web.core.impl.BaseMpServiceImpl;
import com.lframework.starter.web.core.utils.EnumUtil;
import com.lframework.starter.web.core.utils.OpLogUtil;
import com.lframework.xingyun.basedata.bo.member.QueryMemberAccountBo;
import com.lframework.xingyun.basedata.entity.Member;
import com.lframework.xingyun.basedata.entity.MemberAccount;
import com.lframework.xingyun.basedata.enums.BaseDataOpLogType;
import com.lframework.xingyun.basedata.enums.MemberAccountChangeType;
import com.lframework.xingyun.basedata.mappers.MemberAccountMapper;
import com.lframework.xingyun.basedata.service.member.MemberAccountLogService;
import com.lframework.xingyun.basedata.service.member.MemberAccountService;
import com.lframework.xingyun.basedata.service.member.MemberService;
import com.lframework.xingyun.basedata.vo.member.CreateMemberAccountLogVo;
import com.lframework.xingyun.basedata.vo.member.MemberAccountChangeVo;
import com.lframework.xingyun.basedata.vo.member.QueryMemberAccountVo;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.io.Serializable;
import java.util.Objects;

@Service
public class MemberAccountServiceImpl extends BaseMpServiceImpl<MemberAccountMapper, MemberAccount> implements MemberAccountService {

    /**
     * 根据会员ID查询
     * @param memberId 会员ID
     * @return 会员积分账户
     */
    @Cacheable(value = MemberAccount.CACHE_NAME, key = "@cacheVariables.tenantId() + #memberId", unless = "#result == null")
    @Override
    public QueryMemberAccountBo queryByMemberId(String memberId) {
        return new QueryMemberAccountBo(this.getBaseMapper().queryByMemberId(memberId), getThis(MemberService.class).findById(memberId));
    }

    /**
     * 新增会员积分账户
     * @param vo 会员积分账户
     * @return 会员积分账户ID
     */
    @OpLog(type = BaseDataOpLogType.class, name = "新增会员积分账户，ID：{}, 有效积分：{}, 冻结积分：{}", params = {"#id",
            "#effectiveScore", "#freezeScore"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String create(@Validated QueryMemberAccountVo vo) {
        String memberId = vo.getMemberId();
        MemberAccount data = this.getBaseMapper().queryByMemberId(memberId);

        if (Objects.isNull(data)) {
            data = new MemberAccount();
            data.setMemberId(memberId);
            data.setEffectiveScore(vo.getEffectiveScore());
            data.setFreezeScore(vo.getFreezeScore());
            this.getBaseMapper().insert(data);
        }

        OpLogUtil.setVariable("id", data.getId());
        OpLogUtil.setVariable("effectiveScore", data.getEffectiveScore());
        OpLogUtil.setVariable("freezeScore", data.getFreezeScore());
        OpLogUtil.setExtra(vo);
        return data.getId();
    }

    @OpLog(type = BaseDataOpLogType.class, name = "变更会员积分账户积分，memberId：{}, 变动类型：{}, 变动积分：{}, 变动原因：{}",
            params = {"#memberId", "#changeType", "#changeScore", "#changeReason"})
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String changeScore(@Validated MemberAccountChangeVo vo) {
        String memberId = vo.getMemberId();
        MemberAccount memberAccount = this.getBaseMapper().queryByMemberId(memberId);
        Assert.notNull(memberAccount, "会员积分账户不存在！");

        Integer changeType = vo.getChangeType();

        long changeScore = vo.getChangeScore().longValue();
        Assert.state(changeScore != 0, "变动积分不能为0！");
        // 变更类型
        MemberAccountChangeType changeTypeEnum = EnumUtil.getByCode(MemberAccountChangeType.class, changeType);

        //
        if (changeTypeEnum == MemberAccountChangeType.FREEZE_SCORE) {
            // 有效积分变化
            CreateMemberAccountLogVo effectiveScoreLogVo = new CreateMemberAccountLogVo();
            effectiveScoreLogVo.setMemberId(memberId);
            effectiveScoreLogVo.setChangeType(MemberAccountChangeType.EFFECTIVE_SCORE.getCode());
            effectiveScoreLogVo.setBeforeScore(memberAccount.getEffectiveScore());
            effectiveScoreLogVo.setChangeScore(-changeScore);
            memberAccount.setEffectiveScore(memberAccount.getEffectiveScore() + effectiveScoreLogVo.getChangeScore());
            effectiveScoreLogVo.setAfterScore(memberAccount.getEffectiveScore());
            effectiveScoreLogVo.setReason(vo.getChangeReason());
            getThis(MemberAccountLogService.class).add(effectiveScoreLogVo);

            // 冻结积分变化
            CreateMemberAccountLogVo freezeScoreLogVo = new CreateMemberAccountLogVo();
            freezeScoreLogVo.setMemberId(memberId);
            freezeScoreLogVo.setChangeType(MemberAccountChangeType.FREEZE_SCORE.getCode());
            freezeScoreLogVo.setBeforeScore(memberAccount.getFreezeScore());
            freezeScoreLogVo.setChangeScore(changeScore);
            memberAccount.setFreezeScore(memberAccount.getFreezeScore() + freezeScoreLogVo.getChangeScore());
            freezeScoreLogVo.setAfterScore(memberAccount.getFreezeScore());
            freezeScoreLogVo.setReason(vo.getChangeReason());
            getThis(MemberAccountLogService.class).add(freezeScoreLogVo);
        } else if (changeTypeEnum == MemberAccountChangeType.EFFECTIVE_SCORE) {
            // 有效积分变化
            CreateMemberAccountLogVo effectiveScoreLogVo = new CreateMemberAccountLogVo();
            effectiveScoreLogVo.setMemberId(memberId);
            effectiveScoreLogVo.setChangeType(MemberAccountChangeType.EFFECTIVE_SCORE.getCode());
            effectiveScoreLogVo.setBeforeScore(memberAccount.getEffectiveScore());
            effectiveScoreLogVo.setChangeScore(changeScore);
            memberAccount.setEffectiveScore(memberAccount.getEffectiveScore() + effectiveScoreLogVo.getChangeScore());
            effectiveScoreLogVo.setAfterScore(memberAccount.getEffectiveScore());
            effectiveScoreLogVo.setReason(vo.getChangeReason());
            getThis(MemberAccountLogService.class).add(effectiveScoreLogVo);
        }

        // 更新会员积分账户
        getThis(MemberAccountService.class).updateById(memberAccount);

        getThis(MemberAccountService.class).cleanCacheByKey(memberId);

        OpLogUtil.setVariable("memberId", memberId);
        OpLogUtil.setVariable("changeType", changeTypeEnum.getDesc());
        OpLogUtil.setVariable("changeScore", changeScore);
        OpLogUtil.setVariable("changeReason", vo.getChangeReason());
        return memberId;
    }

    @CacheEvict(value = MemberAccount.CACHE_NAME, key = "@cacheVariables.tenantId() + #key")
    @Override
    public void cleanCacheByKey(Serializable key) {

    }
}
